package com.demo.util;

import com.demo.pojo.entity.Schedule;
import com.demo.pojo.entity.Classroom;
import com.demo.pojo.entity.TimeSlot;
import com.demo.pojo.entity.Course;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 智能排课算法工具类
 */
public class ScheduleAlgorithmUtil {
    
    /**
     * 遗传算法参数
     */
    public static final int POPULATION_SIZE = 50;
    public static final int MAX_GENERATIONS = 100;
    public static final double CROSSOVER_RATE = 0.8;
    public static final double MUTATION_RATE = 0.1;
    public static final int TOURNAMENT_SIZE = 5;
    
    /**
     * 模拟退火算法参数
     */
    public static final double INITIAL_TEMPERATURE = 1000.0;
    public static final double COOLING_RATE = 0.95;
    public static final double MIN_TEMPERATURE = 1.0;
    
    /**
     * 计算排课质量分数
     */
    public static double calculateScheduleQuality(List<Schedule> schedules) {
        double score = 0.0;
        
        // 1. 教师时间分布均匀性 (权重: 0.3)
        score += 0.3 * calculateTeacherDistributionScore(schedules);
        
        // 2. 教室利用率 (权重: 0.25)
        score += 0.25 * calculateClassroomUtilizationScore(schedules);
        
        // 3. 学生课程冲突最小化 (权重: 0.25)
        score += 0.25 * calculateStudentConflictScore(schedules);
        
        // 4. 教师偏好满足度 (权重: 0.2)
        score += 0.2 * calculateTeacherPreferenceScore(schedules);
        
        return score;
    }
    
    /**
     * 计算教师时间分布分数
     */
    private static double calculateTeacherDistributionScore(List<Schedule> schedules) {
        Map<Long, List<Schedule>> teacherSchedules = schedules.stream()
                .collect(Collectors.groupingBy(Schedule::getTeacherId));
        
        double totalScore = 0.0;
        for (List<Schedule> teacherSchedule : teacherSchedules.values()) {
            double variance = calculateTimeDistributionVariance(teacherSchedule);
            totalScore += 1.0 / (1.0 + variance);
        }
        
        return teacherSchedules.isEmpty() ? 0.0 : totalScore / teacherSchedules.size();
    }
    
    /**
     * 计算教室利用率分数
     */
    private static double calculateClassroomUtilizationScore(List<Schedule> schedules) {
        Map<Long, Long> classroomUsage = schedules.stream()
                .collect(Collectors.groupingBy(Schedule::getClassroomId, Collectors.counting()));
        
        if (classroomUsage.isEmpty()) return 0.0;
        
        double mean = classroomUsage.values().stream().mapToLong(Long::longValue).average().orElse(0.0);
        double variance = classroomUsage.values().stream()
                .mapToDouble(count -> Math.pow(count - mean, 2))
                .average().orElse(0.0);
        
        return 1.0 / (1.0 + variance);
    }
    
    /**
     * 计算学生冲突分数
     */
    private static double calculateStudentConflictScore(List<Schedule> schedules) {
        int conflicts = 0;
        for (int i = 0; i < schedules.size(); i++) {
            for (int j = i + 1; j < schedules.size(); j++) {
                if (hasStudentConflict(schedules.get(i), schedules.get(j))) {
                    conflicts++;
                }
            }
        }
        
        return 1.0 / (1.0 + conflicts);
    }
    
    /**
     * 计算教师偏好分数
     */
    private static double calculateTeacherPreferenceScore(List<Schedule> schedules) {
        // 简化实现，实际应该根据教师偏好数据计算
        return 0.8;
    }
    
    /**
     * 计算时间分布方差
     */
    private static double calculateTimeDistributionVariance(List<Schedule> schedules) {
        if (schedules.size() <= 1) return 0.0;
        
        List<Integer> timeSlots = schedules.stream()
                .map(Schedule::getTimeSlotId)
                .map(Long::intValue)
                .sorted()
                .collect(Collectors.toList());
        
        double mean = timeSlots.stream().mapToInt(Integer::intValue).average().orElse(0.0);
        return timeSlots.stream()
                .mapToDouble(slot -> Math.pow(slot - mean, 2))
                .average().orElse(0.0);
    }
    
    /**
     * 检查学生冲突
     */
    private static boolean hasStudentConflict(Schedule schedule1, Schedule schedule2) {
        return schedule1.getClazzId().equals(schedule2.getClazzId()) &&
               schedule1.getTimeSlotId().equals(schedule2.getTimeSlotId());
    }
    
    /**
     * 检查教师冲突
     */
    public static boolean hasTeacherConflict(Schedule schedule1, Schedule schedule2) {
        return schedule1.getTeacherId().equals(schedule2.getTeacherId()) &&
               schedule1.getTimeSlotId().equals(schedule2.getTimeSlotId());
    }
    
    /**
     * 检查教室冲突
     */
    public static boolean hasClassroomConflict(Schedule schedule1, Schedule schedule2) {
        return schedule1.getClassroomId().equals(schedule2.getClassroomId()) &&
               schedule1.getTimeSlotId().equals(schedule2.getTimeSlotId());
    }
    
    /**
     * 检查排课冲突
     */
    public static boolean hasScheduleConflict(Schedule schedule1, Schedule schedule2) {
        return hasTeacherConflict(schedule1, schedule2) ||
               hasClassroomConflict(schedule1, schedule2) ||
               hasStudentConflict(schedule1, schedule2);
    }
    
    /**
     * 生成随机排课
     */
    public static Schedule generateRandomSchedule(Course course, List<Classroom> classrooms, 
                                                 List<TimeSlot> timeSlots, Long clazzId) {
        Random random = new Random();
        
        Schedule schedule = new Schedule();
        schedule.setCourseId(course.getCourseId());
        schedule.setTeacherId(course.getTeacherId());
        schedule.setClazzId(clazzId);
        
        // 随机选择教室
        Classroom classroom = classrooms.get(random.nextInt(classrooms.size()));
        schedule.setClassroomId(classroom.getClassroomId());
        
        // 随机选择时间段
        TimeSlot timeSlot = timeSlots.get(random.nextInt(timeSlots.size()));
        schedule.setTimeSlotId(timeSlot.getTimeSlotId());
        
        schedule.setScheduleType("正常");
        schedule.setStatus("ACTIVE");
        schedule.setPriority(3);
        schedule.setIsFixed(0);
        schedule.setCreateTime(new Date());
        schedule.setUpdateTime(new Date());
        
        return schedule;
    }
    
    /**
     * 交叉操作
     */
    public static List<Schedule> crossover(List<Schedule> parent1, List<Schedule> parent2) {
        Random random = new Random();
        int crossoverPoint = random.nextInt(parent1.size());
        
        List<Schedule> offspring = new ArrayList<>();
        offspring.addAll(parent1.subList(0, crossoverPoint));
        offspring.addAll(parent2.subList(crossoverPoint, parent2.size()));
        
        return offspring;
    }
    
    /**
     * 变异操作
     */
    public static List<Schedule> mutate(List<Schedule> individual, List<Classroom> classrooms, 
                                       List<TimeSlot> timeSlots) {
        Random random = new Random();
        if (random.nextDouble() < MUTATION_RATE) {
            int index = random.nextInt(individual.size());
            Schedule schedule = individual.get(index);
            
            // 随机改变教室
            Classroom newClassroom = classrooms.get(random.nextInt(classrooms.size()));
            schedule.setClassroomId(newClassroom.getClassroomId());
            
            // 随机改变时间段
            TimeSlot newTimeSlot = timeSlots.get(random.nextInt(timeSlots.size()));
            schedule.setTimeSlotId(newTimeSlot.getTimeSlotId());
        }
        
        return individual;
    }
    
    /**
     * 锦标赛选择
     */
    public static List<Schedule> tournamentSelection(List<List<Schedule>> population, 
                                                    Map<List<Schedule>, Double> fitness) {
        Random random = new Random();
        List<Schedule> best = null;
        double bestFitness = Double.NEGATIVE_INFINITY;
        
        for (int i = 0; i < TOURNAMENT_SIZE; i++) {
            List<Schedule> candidate = population.get(random.nextInt(population.size()));
            double candidateFitness = fitness.get(candidate);
            if (candidateFitness > bestFitness) {
                best = candidate;
                bestFitness = candidateFitness;
            }
        }
        
        return best;
    }
    
    /**
     * 生成邻域解
     */
    public static List<Schedule> generateNeighbor(List<Schedule> schedules, 
                                                List<Classroom> classrooms, 
                                                List<TimeSlot> timeSlots) {
        List<Schedule> neighbor = new ArrayList<>(schedules);
        Random random = new Random();
        
        if (neighbor.size() >= 2) {
            int index1 = random.nextInt(neighbor.size());
            int index2 = random.nextInt(neighbor.size());
            
            Schedule schedule1 = neighbor.get(index1);
            Schedule schedule2 = neighbor.get(index2);
            
            // 交换教室
            Long tempClassroomId = schedule1.getClassroomId();
            schedule1.setClassroomId(schedule2.getClassroomId());
            schedule2.setClassroomId(tempClassroomId);
            
            // 交换时间段
            Long tempTimeSlotId = schedule1.getTimeSlotId();
            schedule1.setTimeSlotId(schedule2.getTimeSlotId());
            schedule2.setTimeSlotId(tempTimeSlotId);
        }
        
        return neighbor;
    }
    
    /**
     * 解决冲突
     */
    public static boolean resolveConflicts(List<Schedule> schedules, List<Classroom> classrooms, 
                                         List<TimeSlot> timeSlots) {
        boolean hasConflict = true;
        int maxIterations = 100;
        int iteration = 0;
        Random random = new Random();
        
        while (hasConflict && iteration < maxIterations) {
            hasConflict = false;
            
            for (int i = 0; i < schedules.size(); i++) {
                for (int j = i + 1; j < schedules.size(); j++) {
                    Schedule schedule1 = schedules.get(i);
                    Schedule schedule2 = schedules.get(j);
                    
                    if (hasScheduleConflict(schedule1, schedule2)) {
                        hasConflict = true;
                        
                        // 调整优先级低的排课
                        if (schedule1.getPriority() > schedule2.getPriority()) {
                            adjustSchedule(schedule1, classrooms, timeSlots);
                        } else {
                            adjustSchedule(schedule2, classrooms, timeSlots);
                        }
                    }
                }
            }
            
            iteration++;
        }
        
        return !hasConflict;
    }
    
    /**
     * 调整排课
     */
    private static void adjustSchedule(Schedule schedule, List<Classroom> classrooms, 
                                     List<TimeSlot> timeSlots) {
        Random random = new Random();
        
        // 尝试调整到其他教室
        Classroom newClassroom = classrooms.get(random.nextInt(classrooms.size()));
        schedule.setClassroomId(newClassroom.getClassroomId());
        
        // 尝试调整到其他时间段
        TimeSlot newTimeSlot = timeSlots.get(random.nextInt(timeSlots.size()));
        schedule.setTimeSlotId(newTimeSlot.getTimeSlotId());
    }
}
























